#include "cface.h"
#include "tools.h"

CFace::CFace(CMesh * pParent)
{
    this->setEdge1(NULL);
    this->setEdge2(NULL);
    this->setEdge3(NULL);

    this->setVertex1(NULL);
    this->setVertex2(NULL);
    this->setVertex3(NULL);

    this->m_bNormalSet = false;
    this->m_pParentMesh = pParent;

    this->m_pBB = NULL;
}

CFace::~CFace()
{
    delete this->m_pBB;
}

CEdge * CFace::getEdge1()
{
    return this->m_pEdge1;
}

CEdge * CFace::getEdge2()
{
    return this->m_pEdge2;
}

CEdge * CFace::getEdge3()
{
    return this->m_pEdge3;
}

CVertex * CFace::getVertex1()
{
    return this->m_pVertex1;
}

CVertex * CFace::getVertex2()
{
    return this->m_pVertex2;
}

CVertex * CFace::getVertex3()
{
    return this->m_pVertex3;
}

CPoint3f CFace::getNormal()
{
    return this->m_Normal;
}

bool CFace::isNormalSet()
{
    return this->m_bNormalSet;
}

CMesh * CFace::getParentMesh()
{
    return this->m_pParentMesh;
}

void CFace::setEdge1(CEdge * pEdge)
{
    this->m_pEdge1 = pEdge;
}

void CFace::setEdge2(CEdge * pEdge)
{
    this->m_pEdge2 = pEdge;
}

void CFace::setEdge3(CEdge * pEdge)
{
    this->m_pEdge3 = pEdge;
}

void CFace::setVertex1(CVertex * pVertex)
{
    this->m_pVertex1 = pVertex;
}

void CFace::setVertex2(CVertex * pVertex)
{
    this->m_pVertex2 = pVertex;
}

void CFace::setVertex3(CVertex * pVertex)
{
    this->m_pVertex3 = pVertex;
}

void CFace::setupBB()
{
    if (this->getVertex1() != NULL && this->getVertex2() != NULL && this->getVertex3() != NULL )
    {
        if (this->m_pBB)
            delete this->m_pBB;

        this->m_pBB = new CBoundingBox(this, CPoint3f(min(this->getVertex1()->getX(),min(this->getVertex2()->getX(),this->getVertex3()->getX())),
                                                      min(this->getVertex1()->getY(),min(this->getVertex2()->getY(),this->getVertex3()->getY())),
                                                      min(this->getVertex1()->getZ(),min(this->getVertex2()->getZ(),this->getVertex3()->getZ()))),
                                             CPoint3f(max(this->getVertex1()->getX(),max(this->getVertex2()->getX(),this->getVertex3()->getX())),
                                                      max(this->getVertex1()->getY(),max(this->getVertex2()->getY(),this->getVertex3()->getY())),
                                                      max(this->getVertex1()->getZ(),max(this->getVertex2()->getZ(),this->getVertex3()->getZ()))));
    }
}

void CFace::computeNormal()
{
    if (this->getVertex1() != NULL && this->getVertex2() != NULL && this->getVertex3() != NULL )
    {
        CPoint3f V1 (this->getVertex2()->getX() - this->getVertex1()->getX(),
                   this->getVertex2()->getY() - this->getVertex1()->getY(),
                   this->getVertex2()->getZ() - this->getVertex1()->getZ());
        CPoint3f V2 (this->getVertex3()->getX() - this->getVertex2()->getX(),
                   this->getVertex3()->getY() - this->getVertex2()->getY(),
                   this->getVertex3()->getZ() - this->getVertex2()->getZ());
        this->m_Normal = V1.crossProduct(V2);
        this->m_Normal.normalize();
        this->m_bNormalSet = true;
    }
}

void CFace::computeEdges()
{
    CEdge * pE1 = this->getEdge1();
    CEdge * pE2 = this->getEdge2();
    CEdge * pE3 = this->getEdge3();

    if (NULL != pE1)
    {
        pE1->getHead()->removeEdge(pE1);
        pE1->getTail()->removeEdge(pE1);
        if (pE1->getTwinEdge())
            pE1->getTwinEdge()->setTwinEdge(NULL);
        delete pE1;
    }
    if (NULL != pE2)
    {
        pE2->getHead()->removeEdge(pE2);
        pE2->getTail()->removeEdge(pE2);
        if (pE2->getTwinEdge())
            pE2->getTwinEdge()->setTwinEdge(NULL);
        delete pE2;
    }
    if (NULL != pE3)
    {
        pE3->getHead()->removeEdge(pE3);
        pE3->getTail()->removeEdge(pE3);
        if (pE3->getTwinEdge())
            pE3->getTwinEdge()->setTwinEdge(NULL);
        delete pE3;
    }

    pE1 = new CEdge();
    pE1->setFace(this);
    pE1->setHead(this->getVertex1());
    pE1->setTail(this->getVertex2());
    this->setEdge1(pE1);
    this->getVertex1()->addEdge(pE1);
    this->getVertex2()->addEdge(pE1);

    pE2 = new CEdge();
    pE2->setFace(this);
    pE2->setHead(this->getVertex2());
    pE2->setTail(this->getVertex3());
    this->setEdge2(pE2);
    this->getVertex2()->addEdge(pE2);
    this->getVertex3()->addEdge(pE2);

    pE3 = new CEdge();
    pE3->setFace(this);
    pE3->setHead(this->getVertex3());
    pE3->setTail(this->getVertex1());
    this->setEdge3(pE3);
    this->getVertex3()->addEdge(pE3);
    this->getVertex1()->addEdge(pE3);

    pE1->setNextEdge(pE2);
    pE2->setNextEdge(pE3);
    pE3->setNextEdge(pE1);
}
